Namespace.Use("UI.Object", function(ns) {
    //
    //  Imports.
    //
    var Inherit = Namespace.Import("Base.Inherit");

    //
    //  Global.
    //
    var cst_InitialX = 0, cst_InitialY = 0;
    var cst_InitialWidth = 100, cst_InitialHeight = 100;
    var cst_InitialVisibility = true;
    var cst_InitialLayer = 0;
    var cst_InitialBackgroundColor = "transparent";
    var cst_InitialPageID = 0;

    //
    //  Classes.
    //
    var PageContainer = Polymorphic.Create(
        [Array],
        function(pages) {
            //  Let parent class initialize.
            ns.BaseContainer.call(this);

            //  Check the page count.
            if (pages.length == 0) {
                throw "No page available.";
            }

            //  Check the type of page objects.
            for (var idx = 0; idx < pages.length; ++idx) {
                if (!(pages[idx] instanceof ns.BaseObject)) {
                    throw "Invalid object type.";
                }
            }

            //
            //  Members.
            //
            var last_x = -1, last_y = -1;
            var x = cst_InitialX, y = cst_InitialY;
            var last_width = -1, last_height = -1;
            var width = cst_InitialWidth, height = cst_InitialHeight;
            var last_visibility = !cst_InitialVisibility;
            var visibility = cst_InitialVisibility;
            var last_layer = -1;
            var layer = cst_InitialLayer;
            var last_bgcolor = null;
            var bgcolor = cst_InitialBackgroundColor;
            var last_page_id = -1;
            var page_id = cst_InitialPageID;
            var element = $("<div></div>").css({
                "position": "absolute",
                "padding": 0,
                "margin": 0,
                "border": 0
            });
            var invalidate_children = true;

            //
            //  Public methods.
            //
            this.GetHTMLElement = function() {
                return element[0];
            };
            this.Invalidate = function() {
                //  Update the position.
                if (last_x != x) {
                    element.css({
                        "left": x
                    });
                    last_x = x;
                    invalidate_children = true;
                }
                if (last_y != y) {
                    element.css({
                        "top": y
                    });
                    last_y = y;
                    invalidate_children = true;
                }

                //  Update the size.
                if (last_width != width) {
                    element.css({
                        "width": width
                    });
                    last_width = width;
                    invalidate_children = true;
                }
                if (last_height != height) {
                    element.css({
                        "height": height
                    });
                    last_height = height;
                    invalidate_children = true;
                }

                //  Update the visibility.
                if (last_visibility != visibility) {
                    if (visibility == true) {
                        element.show();
                    } else {
                        element.hide();
                    }
                    last_visibility = visibility;
                    invalidate_children = true;
                }

                //  Update the layer.
                if (last_layer != layer) {
                    element.css({
                        "z-index": layer
                    });
                    last_layer = layer;
                    invalidate_children = true;
                }

                //  Update the background color.
                if (last_bgcolor != bgcolor) {
                    element.css({
                        "background-color": bgcolor
                    });
                    last_bgcolor = bgcolor;
                    invalidate_children = true;
                }

                //  Update the page ID.
                if (last_page_id != page_id) {
                    last_page_id = page_id;
                    invalidate_children = true;
                }

                //  Invalidate the children.
                if (invalidate_children == true) {
                    for (var idx = 0; idx < pages.length; ++idx) {
                        var child = pages[idx];
                        child.AccessPosition(0, 0);
                        child.AccessSize(width, height);
                        child.AccessVisibility(idx == page_id);
                    }
                }
            };
            this.AccessPosition = Polymorphic.Create(
                [],
                function() {
                    return [x, y];
                },
                [Number, Number],
                function(new_x, new_y) {
                    last_x = x;
                    last_y = y;
                    x = new_x;
                    y = new_y;
                    this.Invalidate();
                }
            );
            this.AccessSize = Polymorphic.Create(
                [],
                function() {
                    return [width, height];
                },
                [Number, Number],
                function(new_width, new_height) {
                    last_width = width;
                    last_height = height;
                    width = new_width;
                    height = new_height;
                    this.Invalidate();
                }
            );
            this.AccessVisibility = Polymorphic.Create(
                [],
                function() {
                    return visibility;
                },
                [Boolean],
                function(new_visibility) {
                    last_visibility = visibility;
                    visibility = new_visibility;
                    this.Invalidate();
                }
            );
            this.AccessLayer = Polymorphic.Create(
                [],
                function() {
                    return layer;
                },
                [Number],
                function(new_layer) {
                    last_layer = layer;
                    layer = new_layer;
                    this.Invalidate();
                }
            );
            this.AccessPageIndex = Polymorphic.Create(
                [],
                function() {
                    return page_id;
                },
                [Number],
                function(new_page_id) {
                    //  Check the page index.
                    if (new_page_id < 0 || new_page_id >= pages.length) {
                        throw "Out of range.";
                    }

                    //  Set and invalidate.
                    last_page_id = page_id;
                    page_id = new_page_id;
                    this.Invalidate();
                }
            );
            this.QueryChildren = Polymorphic.Create(
                [],
                function() {
                    return this.QueryChildren(null);
                },
                [Function],
                function(object_type) {
                    var result = [];
                    pages.forEach(function(child) {
                        if (object_type === null || (child instanceof object_type)) {
                            result.push(child);
                        }
                    });
                    return result;
                }
            );
            this.HasChild = Polymorphic.Create(
                [ns.BaseObject],
                function(child) {
                    for (var idx = 0; idx < pages.length; ++idx) {
                        if (pages[idx] == child) {
                            return true;
                        }
                    }
                    return false;
                }
            );
            this.AddChild = function() {
                throw "The container is unable to be modified.";
            };
            this.RemoveChild = function() {
                throw "The container is unable to be modified.";
            };

            //  Save the "this" pointer.
            var out = this;

            //  Bind events.
            element.mousedown(function(event) {
                out.TriggerEvent("MouseDown", GetEventOffsetPosition(event));
            }).mousemove(function(event) {
                out.TriggerEvent("MouseMove", GetEventOffsetPosition(event));
            }).mouseup(function(event) {
                out.TriggerEvent("MouseUp", GetEventOffsetPosition(event));
            }).mouseleave(function(event) {
                out.TriggerEvent("MouseLeave", GetEventOffsetPosition(event));
            }).click(function(event) {
                out.TriggerEvent("Click", GetEventOffsetPosition(event));
            });

            //  Add pages.
            for (var idx = 0; idx < pages.length; ++idx) {
                var child = pages[idx];

                //  Check the parent.
                if (child.IsOnDocument()) {
                    throw "Already on document.";
                }

                //  Set the parent of the child.
                child.AccessParent(this);

                //  Add the child to the DOM.
                element.append($(child.GetHTMLElement()));
            }

            //  Invalidate immediately after created.
            this.Invalidate();
        }
    );

    //  Inherit "PageContainer" from "BaseContainer".
    Inherit(PageContainer, ns.BaseContainer);

    //  Export public APIs / classes.
    Namespace.Export(ns, "PageContainer", PageContainer);
});